package tournamentmanager;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

public class XboardMatchRunner extends AbstractMatchRunner {
  private String helperApplication;
  private int matchGames = 1;

  public XboardMatchRunner() {
    if (System.getProperty("os.name").toLowerCase().indexOf("windows") == 0) {
      helperApplication = "\"C:\\Program Files\\WinBoard\\winboard.exe\"";
    }
    else {
      helperApplication = "xboard";
    }
    timeIncrement = -1;
    timeControl = 5;
    movesPerSession = 40;
  }

  public XboardMatchRunner(ChessEngine whitePlayer, ChessEngine blackPlayer) {
    this();
    this.whitePlayer = whitePlayer;
    this.blackPlayer = blackPlayer;
  }

  public void run() {
    Process process = null;
    List<String> command = getCommand();    
    Logger.getLogger(getClass().getName()).fine("Match command: " + getCommandString(command));

    ProcessBuilder pb = new ProcessBuilder(command);
    try {
      process = pb.start();
      if (process.waitFor() != 0) {
        String line;
        StringBuffer errorMsg = new StringBuffer();
        BufferedReader stdErr = new BufferedReader(new InputStreamReader(process.getErrorStream()));
        while ((line = stdErr.readLine()) != null) {
          errorMsg.append(line);
        }
        throw new IOException(errorMsg.toString());
      }
    }
    catch (InterruptedException e) {
      process.destroy();
      throw new RuntimeException("Match interrupted!");
    }
    catch (IOException e) {
      Logger.getLogger(getClass().getName()).log(Level.SEVERE, "process failed!", e);
      throw new RuntimeException("Error from: " + getCommandString(command));
    }
  }

  List<String> getCommand() {
    ArrayList<String> com = new ArrayList<String>();
    if (whitePlayer == null || whitePlayer.getCommand().length() == 0) {
      throw new RuntimeException("Specify engine command!");
    }
    com.add(helperApplication);
    com.add("-xponder");
    com.add("-xexit");
    com.add("-fcp");
    com.add(whitePlayer.getCommand());
    if (whitePlayer.getWorkingDirectory().length() > 0) {
      com.add("-fd");
      com.add(whitePlayer.getWorkingDirectory());
    }
    if (blackPlayer != null) {
      com.add("-scp");
      com.add(blackPlayer.getCommand());
      if (blackPlayer.getWorkingDirectory().length() > 0) {
        com.add("-sd");
        com.add(blackPlayer.getWorkingDirectory());
      }
    }
    if (timeControl != 5) {
      com.add("-tc");
      com.add(String.valueOf(timeControl));
    }
    if (timeIncrement > -1) {
      com.add("-inc");
      com.add(String.valueOf(timeIncrement));
    }
    if (movesPerSession != 40) {
      com.add("-mps");
      com.add(String.valueOf(movesPerSession));
    }
    if (saveGameFile.length() > 0) {
      com.add("-sgf");
      com.add(String.valueOf(saveGameFile));
    }
    if (blackPlayer != null) {
      com.add("-mg");
      com.add(String.valueOf(matchGames));
    }
    return com;
  }

  String getCommandString(List<String> command) {
    StringBuilder buf = new StringBuilder();
    for (String arg : command) {
      buf.append(arg);
      buf.append(" ");
    }
    return buf.toString().trim();
  }

  public void setMatchGames(int matchGames) {
    if (matchGames < 1) {
      this.matchGames = 1;
    }
    this.matchGames = matchGames;
  }

  public void setHelperApplication(String helperApplication) {
    this.helperApplication = helperApplication;
  }

}
